<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://best.openssf.org/assets/css/style.css">
<link rel="stylesheet" href="checker.css">
<script src="checker.js"></script>
<script src="csp1.js"></script>
<link rel="license" href="https://creativecommons.org/licenses/by/4.0/">

<!-- See create_labs.md for how to create your own lab! -->

</head>
<body>
<!-- For GitHub Pages formatting: -->
<div class="container-lg px-3 my-5 markdown-body">
<h1>Lab Exercise csp1</h1>
<p>
This is a lab exercise on developing secure software.
For more information, see the <a href="introduction.html" target="_blank">introduction to
the labs</a>.

<p>
<h2>Task</h2>
<p>
<b>Please change the code below so that this server-side JavaScript
web application will have many security hardening headers, including a
special configuration of its Content Security Policy (CSP).</b>

<p>
<h2>Background</h2>
<p>
In this exercise, we'll add security headers to a server-side
web application.
This server-side program is written in JavaScript using the
Express framework (version 4).
We'll be using the
<a href="https://helmetjs.github.io/"><tt>helmet</tt></a> library, which
helps add hardening headers to Express applications.

<p>
<h2>Task Information</h2>
<p>

<p>
You'll first need to load the <tt>helmet</tt> library.
There are many ways to do this in JavaScript.
In this case, we'll use a <tt>require</tt> statement to load
a library.
Look at the line below to require Express, and create a similar
line to require helmet.

<p>
We now need to write code to use helmet to insert hardening headers.
In Express you can use an <tt>app.use(...)</tt> call to indicate
something to use on every request.
You <i>could</i> simply call helmet like this, and it would set up
many hardening headers:

<pre>
app.use(helmet());
</pre>

<p>
However, it's very common to need to specially configure this
for your application.
The helmet() call accepts an optional object that lets you configure things.
In JavaScript an object is noted as <tt>{</tt> ... <tt>}</tt>,
where its contents are a comma-separated sequence of key-value pairs.
Each key-value pair has a field name, a colon (:), and its corresponding value.

<p>
In this case we want to modify the configuration of the
Content Security Policy (CSP).
You can indicate this by setting the field name
<tt>contentSecurityPolicy</tt> to a value.
This value is another object. This would look like this:

<pre>
app.use(helmet({
  contentSecurityPolicy: {
  }
}));
</pre>

<p>
The value object for <tt>contentSecurityPolicy</tt>
can itself have various fields, including
the field <tt>directives</tt>.
This field <tt>directives</tt> in turn takes a JavaScript object
as its value.

<p>
The object of the <tt>directives</tt> field
can take one or more keys. In our case we'll want to set two:

<ul>
<li>"script-src": This will set the
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src">CSP script-src directive</a>,
which specifies valid sources for JavaScript for the client to run.
Like any security setting, you want to minimize these privileges.
<li>"style-src": This will set the CSP style-src directive, which specifies
where styles can be loaded from.
</ul>

<p>
One quirk about JavaScript syntax: keys that have a dash ("-")
character in it, like these, must be represented as strings
(surround the term with double quotes).

<p>
In the case of "script-src", for our purposes set it to the array
<tt>["'self'", "https://example.com"]</tt>.
This means that JavaScript can be run from either this server
<i>or</i> from the website
<tt>https://example.com</tt> - and nowhere else.
Note that <tt>'self'</tt> is itself quoted.
We could have also included
"unsafe-inline" which would allow the use of inline JavaScript.
However, we won't do that in this example, because it's much safer
to <i>not</i> include "unsafe-inline".
When a CSP "script-src" value is set, and it doesn't include
"unsafe-inline", that means that JavaScript embedded in some HTML
will <i>not</i> be executed.
This is great for security; often attackers can trick servers into
slipping something into some generated HTML, and this means that if
it's a script, it won't be executed.

<p>
Set "style-src" to <tt>["'self'"]</tt> - that states that
styles can <i>only</i> come from this site (and nowhere else).
Again, we didn't include
"unsafe-inline", that means that CSS embedded in the HTML will be ignored.
This is good for security, because it means that even if an attacker
tricks a server into embedding some CSS commands, those commands will
be ignored.

<p>
Use the “hint” and “give up” buttons if necessary.

<!-- TODO: Discuss inline -->

<!--
???
<pre>
app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      "script-src": ["'self'", "https://example.com"],
      "style-src": ["'self'"]
    },
  }
}));
</pre>

Please change the code below so the query parameter
<tt>id</tt> <i>must</i> be an integer between 1 and 9999 (including
those numbers).

<p>
To do that,
after the first parameter to <tt>app.get</tt>
which says <tt>'/invoices'</tt>,
add a new comma-separated parameter.
Start this new parameter with
<tt>query('id')</tt> to select the
<tt>id</tt> parameter for validation (we've filled in this part
to help get you started).
After <tt>query('id')</tt> (and before the terminating comma),
add a period (<tt>.</tt>) and the validation requirement
<tt>isInt()</tt> (<tt>isInt</tt> validates that the named parameter is
an integer).
The <tt>isInt</tt> method takes, as an optional parameter inside
its parentheses,
an object providing a minimum and maximum, e.g.,
<tt>isInt({min: YOUR_MINIMUM, max: YOUR_MAXIMUM})</tt>.
Set <tt>min</tt> and <tt>max</tt> to specify the allowed range.

<p>
Note: JavaScript names are case-sensitive, so <tt>isint</tt> won't work.
Remember to indicate the end of this parameter with a comma
(our starter text does this).

<p>
You can use the buttons below to ask for a hint, reset the
input to its initial state, or give up (and show an answer) -
but please try to do this on your own!

<p>
// Based on https://helmetjs.github.io/
// npm install helmet ; version 7.1.0

// Use require(), not import..from, so it works in more places.
//
// In helmet 7.1.0 the CSP defaults are:
// Content-Security-Policy: default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests
// 'unsafe-inline'
//
// Run with:
//   node csp1.js
// Then view with:
//   curl --verbose 'http://localhost:3000'
-->

<p>
<h2>Interactive Lab (<span id="grade"></span>)</h2>
<p>
<form id="lab">
<pre><code
>const express = require("express");
<input id="attempt0" type="text" size="60" spellcheck="false" value="const">

const app = express();

// Use Helmet to insert hardening headers
<textarea id="attempt1" rows="10" cols="60" spellcheck="false">
app.use(
);
</textarea>

app.get("/", (req, res) => {
  res.send("Hello world!");
});

app.listen(3000);
</code></pre>
<button type="button" class="hintButton">Hint</button>
<button type="button" class="resetButton">Reset</button>
<button type="button" class="giveUpButton">Give up</button>
<br><br>
<p>
<i>This lab was developed by David A. Wheeler at
<a href="https://www.linuxfoundation.org/"
>The Linux Foundation</a>.</i>
<br><br>
<p id="correctStamp" class="small">
<textarea id="debugData" class="displayNone" rows="20" cols="65" readonly>
</textarea>
</form>
</div><!-- End GitHub pages formatting -->
</body>
</html>
